#include "ServerClientTools.h"
#include "SocketSendRecvTools.h"
#include "GeneralFunctions.h"
#include <WinSock2.h>

#define SEND_STR_SIZE 100
#define CONNECT_WAIT_TIME 200
#define DEBUG_MODE

static DWORD ServiceThread( SOCKET *t_socket ) ;

SOCKET StartServer(char *ServerIpString, int ServerPort)
{
	int ListenRes ;
	SOCKET MainSocket = INVALID_SOCKET;
	unsigned long Address;
	SOCKADDR_IN service;
	int bindRes;
	// Initialize Winsock.
    WSADATA wsaData; 
    int StartupRes = WSAStartup( MAKEWORD( 2, 2 ), &wsaData );	           

    if ( StartupRes != NO_ERROR )
	{
        printf( "error %ld at WSAStartup( ), ending program.\n", WSAGetLastError() );
		// Tell the user that we could not find a usable WinSock DLL.                                  
		return -1;
	}
 
    /* The WinSock DLL is acceptable. Proceed. */

    // Create a socket.    
    MainSocket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );

    if ( MainSocket == INVALID_SOCKET ) 
	{
        printf( "Error at socket( ): %ld\n", WSAGetLastError( ) );
		//goto server_cleanup_1; 
    }

    // Bind the socket.
	/*
		For a server to accept client connections, it must be bound to a network address within the system. 
		The following code demonstrates how to bind a socket that has already been created to an IP address 
		and port.
		Client applications use the IP address and port to connect to the host network.
		The sockaddr structure holds information regarding the address family, IP address, and port number. 
		sockaddr_in is a subset of sockaddr and is used for IP version 4 applications.
   */
	// Create a sockaddr_in object and set its values.
	// Declare variables

	Address = inet_addr( ServerIpString );
	if ( Address == INADDR_NONE )
	{
		printf("The string \"%s\" cannot be converted into an ip address. ending program.\n",
				ServerIpString);
		// goto server_cleanup_2; 
	}

    service.sin_family = AF_INET;
    service.sin_addr.s_addr = Address;
    service.sin_port = htons( ServerPort ); //The htons function converts a u_short from host to TCP/IP network byte order 
	                                   //( which is big-endian ).
	/*
		The three lines following the declaration of sockaddr_in service are used to set up 
		the sockaddr structure: 
		AF_INET is the Internet address family. 
		"127.0.0.1" is the local IP address to which the socket will be bound. 
	    2345 is the port number to which the socket will be bound.
	*/

	// Call the bind function, passing the created socket and the sockaddr_in structure as parameters. 
	// Check for general errors.
    bindRes = bind( MainSocket, ( SOCKADDR* ) &service, sizeof( service ) );
	if ( bindRes == SOCKET_ERROR ) 
	{
        printf( "bind( ) failed with error %ld. Ending program\n", WSAGetLastError( ) );
		// goto server_cleanup_2;
	}
	#ifdef DEBUG_MODE
		printf("DEBUG: Finished starting up the server with IP: %s and port %d\n", ServerIpString, ServerPort);
	#endif
	// Listen on the Socket.
	ListenRes = listen( MainSocket, SOMAXCONN );
    if ( ListenRes == SOCKET_ERROR ) 
	{
        printf( "Failed listening on socket, error %ld.\n", WSAGetLastError() );
	//	goto server_cleanup_2;
	}
	return MainSocket;
}


SOCKET AcceptConnection(SOCKET MainSocket)
{
	SOCKET AcceptSocket ;	
	#ifdef DEBUG_MODE
		printf( "Waiting for a client to connect...\n" );
	#endif
    AcceptSocket = accept( MainSocket, NULL, NULL );
	if ( AcceptSocket == INVALID_SOCKET )
		{
			printf( "Accepting connection with client failed, error %ld\n", WSAGetLastError() ) ; 
	//	goto server_clea
		}
	printf( "Client Connected.\n" );
	return AcceptSocket;
}



SOCKET StartClientAndConnectToServer(char *ServerIpString, int ServerPort)
{
	int ConnectRes = SOCKET_ERROR;
	SOCKADDR_IN clientService;
	SOCKET m_socket;
	int AttemptsCounter = 0;
    // Initialize Winsock.
    WSADATA wsaData; //Create a WSADATA object called wsaData.
	//The WSADATA structure contains information about the Windows Sockets implementation.
	
	//Call WSAStartup and check for errors.
    int iResult = WSAStartup( MAKEWORD(2, 2), &wsaData ); 
    if ( iResult != NO_ERROR )
		PrintErrorAndExit(ERROR_AT_WSAStartup);

	//Call the socket function and return its value to the m_socket variable. 
	// For this application, use the Internet address family, streaming sockets, and the TCP/IP protocol.
	
	// Create a socket.
    m_socket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );

	// Check for errors to ensure that the socket is a valid socket.
    if ( m_socket == INVALID_SOCKET ) {
        printf( "Error at socket(): %ld\n", WSAGetLastError() );
        WSACleanup();
        return -1;
    }
	/*
	 The parameters passed to the socket function can be changed for different implementations. 
	 Error detection is a key part of successful networking code. 
	 If the socket call fails, it returns INVALID_SOCKET. 
	 The if statement in the previous code is used to catch any errors that may have occurred while creating 
	 the socket. WSAGetLastError returns an error number associated with the last error that occurred.
	 */


	//For a client to communicate on a network, it must connect to a server.
    // Connect to a server.

    //Create a sockaddr_in object clientService and set  values.
    clientService.sin_family = AF_INET;
	clientService.sin_addr.s_addr = inet_addr( ServerIpString ); //Setting the IP address to connect to
    clientService.sin_port = htons( ServerPort ); //Setting the port to connect to.
	
	/*
		AF_INET is the Internet address family. 
	*/


    // Call the connect function, passing the created socket and the sockaddr_in structure as parameters. 
	// Check for general errors.
	#ifdef DEBUG_MODE
		printf("DEBUG: Trying to connect to server with IP %s and port %d\n", ServerIpString, ServerPort);
	#endif

		while (ConnectRes == SOCKET_ERROR)
	{
		
		ConnectRes = connect( m_socket, (SOCKADDR*) &clientService, sizeof(clientService) );
		#ifdef DEBUG_MODE
			printf("DEBUG: Can't connect to server, trying again in %d miliseconds\n", CONNECT_WAIT_TIME);
			AttemptsCounter++;
			/*if (AttemptsCounter == 5)
				getchar();*/
		#endif
		Sleep(CONNECT_WAIT_TIME);

	}
		
	return m_socket;

    // Send and receive data.
	/*
		In this code, two integers are used to keep track of the number of bytes that are sent and received. 
		The send and recv functions both return an integer value of the number of bytes sent or received, 
		respectively, or an error. Each function also takes the same parameters: 
		the active socket, a char buffer, the number of bytes to send or receive, and any flags to use.

	*/	

}